package smallfrench.moteur.biblio;

import smallfrench.moteur.biblio.err.ErreurParametres;
import smallfrench.moteur.interp.RObjet;

/**
 * Représente la classe d’un flottant.
 * 
 * @author antoine1023
 *
 */
public class RClasseFlottant extends RClasse {

	public static final RClasseFlottant CLASSE = new RClasseFlottant();

	private RClasseFlottant() {

		super(new RClasse[] {RClasse.CLASSE});

		champs.put("abs", fnAbs);
		champs.put("cos", fnCos);
		champs.put("sin", fnSin);
		champs.put("tan", fnTan);
		champs.put("arccos", fnArccos);
		champs.put("arcsin", fnArcsin);
		champs.put("arctan", fnArctan);
		champs.put("carre", fnCarre);
		champs.put("racineCarree", fnRacineCarree);
		champs.put("enChaine", fnEnChaine);
		champs.put("enEntier", fnEnEntier);
	}



	@Override
	public RFlottant appeler(RObjet moi, RObjet[] params) {

		if (params.length == 0) {

			return new RFlottant(0.0d);

		} else if (params.length == 1) {

			RObjet arg = params[0];

			if (arg instanceof REntier) {
				REntier f = (REntier)arg;
				return new RFlottant(f.valeur);

			} else if (arg instanceof RChaine) {
				RChaine c = (RChaine)arg;
				String s = c.valeur.replace(',', '.');

				try {
					return new RFlottant(Double.parseDouble(s));
				} catch (NumberFormatException e) {
				}

			} else if (arg instanceof RFlottant) {
				return (RFlottant) arg;
			}

		}

		throw ErreurParametres.nouvelleException();
	}

	//---------------------------------------------------

	private static abstract class Fonction extends RFonction {

		public abstract RObjet appeler2(RFlottant moi, RObjet[] params);

		@Override
		public final RObjet appeler(RObjet moi, RObjet[] params) {
			if (moi instanceof RFlottant)
				return appeler2((RFlottant)moi, params);
			return null;
		}
	}

	//---------------------------------------------------

	/**
	 * Valeur absolue
	 */
	private final Fonction fnAbs = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new RFlottant(Math.abs(moi.valeur));
		}
	};


	private final Fonction fnCos = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new RFlottant(Math.cos(moi.valeur));
		}
	};
	private final Fonction fnSin = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new RFlottant(Math.sin(moi.valeur));
		}
	};
	private final Fonction fnTan = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new RFlottant(Math.tan(moi.valeur));
		}
	};
	private final Fonction fnArccos = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new RFlottant(Math.acos(moi.valeur));
		}
	};
	private final Fonction fnArcsin = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new RFlottant(Math.asin(moi.valeur));
		}
	};
	private final Fonction fnArctan = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new RFlottant(Math.atan(moi.valeur));
		}
	};

	private final Fonction fnCarre = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new RFlottant(moi.valeur * moi.valeur);
		}
	};
	private final Fonction fnRacineCarree = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new RFlottant(Math.sqrt(moi.valeur));
		}
	};

	private final Fonction fnEnChaine = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return moi.enChaine();
		}
	};

	/**
	 * Troncature
	 */
	private final Fonction fnEnEntier = new Fonction() {
		@Override
		public RObjet appeler2(RFlottant moi, RObjet[] params) {
			return new REntier((long)moi.valeur);
		}
	};

	@Override
	public RChaine enChaine() {
		return new RChaine("Flottant");
	}

}
